        TITL DAI FIRMWARE C7FB-CA00  V1.1
        ORG   :C7FB
*
*
*
*********************************
* CHECK FOR HIGHEST RAM ADDRESS *
*********************************
*
* Entry: No conditions.
* Exit:  HL points after RAM.
*        BC preserved, ADEF corrupted.
*
MEMCHK  LXI   D,:1000
        LXI   H,:0000   Start at 0000
MCK10   DAD   D         Incr. with #1000
        MOV   A,M       Get what is in memory
        CMA             Take its complement
        MOV   M,A       and store it back
        CMP   M         Then compare
        CMA
        MOV   M,A       Restore original value
        JZ    :C801     Next block if still RAM
        RET
*
**********************
* START FROM SCRATCH *
**********************
*
* Entry to Basic monitor.
*
 REM
* If out of a Hard BREAK:
 REM
RSTART  LXI   SP,:F900  Reset stackpointer
        CALL  :CEE4     Select ROM bank 0,
        DBL   :DBB8     print '*** BREAK'
 REM
* Re-enter Basic after run-time error,
* except on input:
 REM
START   XRA   A
        STA   :0135     Input from keyb/DINC
 REM
* Entry on reset, after encoding program line,
* after END:
 REM
ST10    LXI   H,:F900
        SHLD  :0127     Reset current base stack
        SPHL            Reset stackpointer
        XRA   A
        STA   :0126     No suspended program
 REM
* Restart interpreter; entry after end of program,
* after direct command, after soft BREAK, after
* direct command error, after STOP:
 REM
ST20    LHLD  :0127     Get saved stackpointer
        SPHL            Set it to saved value
*
*
*
**********************
* START FROM SCRATCH *
**********************
*
* Added is the reset of all keyboard pointers at
* various moments:
* - When restarting the Basic interpreter.
* - After command execution. Then also the output
*   direction is reset to screen (to avoid a not
*   useable keyboard).
* - Idem before executing 'break'.
* Resetting the keyboard pointers clears the key
* input buffer in order to avoid keybounce.
*
        CALL  :D563     ] Keyb. pntrs to default
        LXI   H,:0000
        SHLD  :0100
        SHLD  :0104
        SHLD  :0113
        MOV   A,H
        STA   :0122
*
        LXI   H,:0117
        MOV   M,A       No running of inputs
        INX   H
        MOV   M,A       No running of program
        CALL  :D988     Enable keyboard interrupt
        CALL  :D9DB     Enable clock interrupt
ST23    LDA   :0135     Get input direction
        CPI   :02
        CZ    :D879     EFSW=2: input from editbuf
        JNC   :C867     encode text line if edit
        MVI   A,:2A     buffer not empty
        CALL  :DD1A     Print '*', scan keyboard
 REM and display characters
 REM until Break or car.ret
 REM (If no input is given,
 REM the DAI remains here in a
 REM endless loop).
        JC    :C846     If BREAK: new inputs
        CALL  :DDD2     Get char from line, neglect
 REM TAB and space
        CPI   :0D
        JZ    :C846     If car.ret: new inputs
        CALL  :DE0D     Check if char is number
        JNC   :C86D     If no leading nr: encode cmd
 REM
* Encode program line (if 1st char is number):
 REM
ST24    CALL  :C918     Encode program line, update
 REM program
        JMP   :C818     Get next input line; kill
 REM any suspended program
 REM
* Encode direct command (if 1st char is no number):
 REM
ST25    MVI   D,:80     Mask for direct command
        PUSH  H         Pointer to RUNF
        LXI   H,:013F   Addr EBUF
        PUSH  H         Save it on stack
        RST   1         Encode immediate cmd line
        DATA  :00
        MVI   M,:00     Dummy end of program
        CALL  :DD5E     Print car.ret
        POP   B         Get EBUF pntr
        POP   H         Pntr to RUNF
        MVI   M,:FF     Set flag running programs
 REM
* Run a Basic line:
 REM
ST30    LDAX  B         Get 1st byte from EBUF:
 REM <  #80: length,
 REM >= #80: Token.
ST35    INX   B
        ADD   A         Calc offset from CF00
        JNC   :C8E5     Jump if length byte
        MOV   L,A       Get table address in HL
        MVI   H,:CF
        MOV   A,M       ) Get addr Basic routine
        INX   H         ) from table in HL
        MOV   H,M       )
        MOV   L,A       )
        CALL  :C8A9     Perform this routine
 REM
* Commands return here:
 REM
ENDCOM  JC    :C8AA     Jump if special action
 REM
* If suspended:
 REM
        MOV   H,B
        MOV   L,C
        SHLD  :0102     Remember start next cmd
        LXI   H,:02C4   ]
        MOV   A,M       ] Get break flag
        ORA   A
        JZ    :C87F
        CALL  :D563     ] Keyb.pntrs to default
        XRA   A         ]
        STA   :0131     ] Output to screen
        JMP   :C8C0     Handle break
 REM
* Run a BASIC line:
 REM
DCALL   PCHL            Addr Basic routine in PC
 REM
* If special end of action:
 REM
ST40    CPI   :02
*
        JZ    :C89F     ] Keyb.pntrs to default,
 REM output to screen
        JNC   :C8B8     If STOP (3)
        JPE   :C818     If can't continu (1)
        JMP   :C908     If after LOAD (0)
 REM
* If 'STOP':
 REM
ST45    MOV   H,B
        MOV   L,C
        SHLD  :0102     Remember where next cmd
        JMP   :C8C5     Print 'IN LINE ..' and
 REM handle a break
 REM
* If suspended (soft Break handling):
 REM
ST50    CALL  :DAFF     Print car.ret; 'BREAK'.
        DBL   :DBC5
ST55    CALL  :DA75     Print 'IN LINE .....'
 REM or car.ret
        JZ    :C823     Jump if immediate cmd
 REM
* Only if 'break' in program:
 REM
        LXI   H,:FFEB   Frame length
        DAD   SP        New stack level
        MOV   B,H
        MOV   C,L
        SHLD  :0127     Set new base stack
        SPHL            Set stackpointer
        LXI   D,:0100   ) Boundaries frame
        LXI   H,:0115   )
        CALL  :DE4F     Save program status
 REM (FRAME) on stack.
        LXI   H,:0126
        INR   M         Set flag existence saved
 REM program
        JMP   :C823     Run again
 REM
* Length byte or end flag:
 REM
ST60    JZ    :C823     If end immediate cmd
 REM line or end program
        MOV   H,B
        MOV   L,C
        SHLD  :0100     Store start current line
        LHLD  :0115     Get trace + step flag
        MOV   A,H
        ORA   L
        JZ    :C900     If no step/trace flag
 REM
* If step/trace flag set:
 REM
        PUSH  H
        PUSH  B
        CALL  :CEA4     List current line
        POP   B
        POP   PSW       Get step flag
        ORA   A         If set:
        CNZ   :D6DA     Wait for spacebar pressed
ST65    INX   B
        INX   B         Pnts after linenr
        JC    :C8CB     If Break
        JMP   :C87F     Run next BASIC line
 REM
* Special action after LOAD:
 REM
ST70    LHLD  :0100     Get start current line
        MOV   A,H
        ORA   L         Direct cmd?
        JZ    :C87F     Then run Basic line
        LXI   SP,:F900  Else: reset stackpointer
        MVI   A,:87     Simulate Token 'RUN'
        JMP   :C880     Pretend RUN cmd
*
* PROGRAM INPUT:
*
* Encodes a program line and updates the stored
* program.
*
* Entry: C: Input count / offset.
* Exit:  C: Offset after line.
*        AFBDEHL preserved.
*
PROGI   LXI   H,:013F   Addr buf for encoded cmds
        RST   1         Get linenr
        DATA  :03
        CALL  :DDD2     Get char from line;
 REM neglect TAB + space
        CPI   :0D       Car.ret ?
        CZ    :C9A2     Delete old version if
 REM only linenr given
        JZ    :C93B     Jump if linenr only
        PUSH  D         Remember linenr
        MVI   D,:40     Mask for 'stored cmd'
        CALL  :C93C     Encode a line
        MOV   A,L
        SUI   :3F       Length string in A
        STA   :013E     Length in EBUF
        POP   D         Get linenr
        CALL  :C9A2     Delete old line
        CALL  :C9BD     Insert new line
PGI20   RET
*
* ENCODE A LINE:
*
* Exit: DE restored.
*       HL points to 1st free byte in EBUF.
*        C points after car.ret in input.
*        A=0, F corrupted.
*
ELINA   PUSH  D
        PUSH  B
        PUSH  H
        LXI   H,:0000
        DAD   SP        Stackpointer in HL
        SHLD  :011D     Save stackpointer
        POP   H
        PUSH  H
        MVI   A,:01
        STA   :0122     Set encoding a stored line
        RST   1         Encode inputs
        DATA  :00
        POP   D         ) Cancel Push B,H
        POP   D         )
ELA10   XRA   A
        STA   :0122     No encoding stored line
        POP   D
        RET
*
**************************************
* ERROR WHILE ENCODING A STORED LINE *
**************************************
*
* Restores stackpointer, adds '***' to begin of
* line, adds '?' to place of error. Line is entered
* into the encoded inputbuffer (EBUF).
*
* Entry: B: Errorcode.
*        C: Place of error.
*        On stack: BC points to input.
*                  HL points to EBUF.
*
ELARS   LHLD  :011D     Get ERSSP
        SPHL            Restore stackpointer
        POP   H         Get buffer pointer
        MOV   A,B       Errorcode in A
        MOV   D,C       Place of error in D
        POP   B         Get input pointer
        MOV   B,A
        MVI   M,:B1     Token for '***' in EBUF
        INX   H
        PUSH  H         Save buf pointer
        INX   H
ELA20   MOV   A,C       ) Place of error
        CMP   D         ) reached ?
        MVI   A,:3F
        CZ    :C995     Then insert '?'
        CALL  :DDE0     Get char. from line
        INR   C         Update inputpointer
        CPI   :0D       Line done ?
        CNZ   :C995     Insert char in EBUF if not
        JNZ   :C965     Next char if not ready
        MOV   A,L       Lobyte EBUF pntr in A
        POP   D         Addr after '***'
        SUB   E
        DCR   A
        STAX  D         Store length in EBUF
        MVI   M,:00     0 after string
        PUSH  B         Save errormessage pntr
        MOV   B,D       ) EBUF pntr in BC
        MOV   C,E       )
        DCX   B
        DCX   B
        DCX   B
        DCX   B         Pnts to begin EBUF
        CALL  :DD5E     Print car.ret
        CALL  :ECAB     (0) List current line
        POP   B         Get errormessage pntr
        PUSH  H
        CALL  :DA50     Print errormessage
        POP   H
        JMP   :C951     Store 0 in ERSFL, Pop D,
 REM and ret.
*
* INSERT CHARACTER IN ENCODED INPUT BUFFER:
*
* A character is inserted in the EBUF only if
* there is space available.
*
* Entry: HL: 1st free location in EBUF.
*        A:  Character to be inserted.
* Exit:  HL updated. AFBCDE preserved.
*
ELAIN   PUSH  PSW
        MOV   A,L       Get lobyte of EBUF pntr
        CPI   :BC       Buffer full ?
        JZ    :C9A0     Then abort
        POP   PSW
        MOV   M,A       Char into EBUF
        INX   H         Update pntr
        RET
 REM
* If EBUF full:
 REM
EAI10   POP   PSW       No action
        RET
*
********************************
* DELETE OLD VERSION OF A LINE *
********************************
*
* A textline is deleted by moving the rest of the
* textbuffer and the symboltable 'downwards'.
*
* Entry: DE: requested linenumber.
* Exit:  DE points to linenr after deleted line.
*        AFBCHL preserved.
*
LDEL    PUSH  PSW
        PUSH  B
        PUSH  H
        XCHG            Linenr in HL
        CALL  :CAF6     Addr line in textbuf in HL
        JNC   :C9B8     Abort if not found
        MOV   A,M       Get line length
        CMA
        MOV   E,A       Compl. value in E
        MVI   D,:FF
        CALL  :DE39     HL=HL-line length
        XCHG
        CALL  :C9D1     Move program buffers
LDL10   XCHG
        POP   H
        POP   B
        POP   PSW
        RET
*
*********************
* INSERT A NEW LINE *
*********************
*
* Inserts a encoded line in the textbuffer.
* Required space for the textline is made by
* shifting the rest of the textbuffer and the
* symboltable 'upwards'.
*
* Entry: DE: Destination address in textbuffer.
*        HL: Points after string in EBUF.
*        A:  Length string in EBUF.
*
LINS    PUSH  B
        PUSH  H
        MOV   L,A
        MVI   H,:00     String length in HL
        INX   H         Required space in HEAP
        PUSH  D
        CALL  :C9D1     Move program buffers
        POP   B
        POP   H
        LXI   D,:013E   Startaddr. EBUF
        CALL  :DE4F     Transfer data from EBUF
 REM into textbuffer
        POP   B
        RET
*
************************
* MOVE PROGRAM BUFFERS *
************************
*
* Moves a part (or the whole) textbuffer and the
* whole symboltable up or down.
* The startaddress of the textbuffer and the end
* of the symboltable are set depending on the
* heap size. The heap pointers are updated.
*
* Entry: DE: Address from where to update.
*        HL: Length of area to be inserted/deleted.
* Entry if running 'NEW' only:
*        BC: 0.
*        DE: startaddress Heap.
*        HL: Size Heap.
*        At entry, the pointers for textbuf and
*        symtab are as if HEAPsize is zero.
* Exit:  AFBCDE preserved.
*        HL: New startaddress.
*
PROGM   PUSH  B
        PUSH  D
        MOV   B,D       ) Addr from where to
        MOV   C,E       ) update in BC
        XCHG            Length area in DE
        LHLD  :02A3     Get end symtab
        PUSH  H
        PUSH  D
        DAD   D         New end symtab
        XCHG
        LHLD  :02A5     Get bottom screen RAM
        CALL  :DE14     Check for overflow
        XCHG            End symtab in HL
        JC    :DA10     Evt. run 'OUT OF MEMORY'
        SHLD  :02A3     Store end symbol table
        POP   D
        PUSH  D
        LHLD  :02A1     Get begin symtab
        DAD   D         New begin symtab
        SHLD  :02A1     Store begin symbol table
PRGM1   POP   H
        MOV   D,B
        MOV   E,C       Startaddr in DE
        DAD   D         New startaddr
        MOV   B,H
        MOV   C,L       New startaddr in BC
        XTHL            Get old end symtab
        CALL  :DE4F     Move textbuf + symtab
 REM from old to new addr.
        POP   H
        POP   D
        POP   B
        RET
*
*
*
        END
